package edu.wpi.cs509.ui;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import edu.wpi.cs509.common.exceptions.InitialPlacementError;
import edu.wpi.cs509.representation.Location;
import edu.wpi.cs509.representation.PlayerPiece;
import edu.wpi.cs509.ui.images.StrategoPieceImage;
import edu.wpi.cs509.ui.intfc.GameInterface;

/**
 * The GameWindow is the object instantiated each time a new window is opened
 * for either playing or observing a game.
 * 
 * @author afoltan
 *
 */
public class GameWindow {

	// the main app window
	private A__MainStrategoClient client;
	
	// the game object for this window
	private GameInterface game;
	
	// frame view of the game window
	private GameWindowFrame frame;
	
	/**
	 * Contructor
	 * @param client - the main client application object
	 */
	public GameWindow( A__MainStrategoClient client ) {
		this.client = client;
	}

	public A__MainStrategoClient getClient() {
		return client;
	}
	/*
	public GameInterface getGameInterface() {
		return game;
	}
	*/
	/**
	 * Assigns the game object to this window.  This call occurs after the
	 * client logic notify is sent from the server.
	 * @param game - the game object
	 */
	public void setGameInterface( GameInterface game ) {
		System.out.println("Game window being created.");
		this.game = game;
		frame = new GameWindowFrame( this, game );
		frame.pack();
		
	}
	/** Returns the GameWindowFrame associated with this game.
	 * 
	 * @return a GameWindowFrame
	 */
	public GameWindowFrame getGameWindowFrame(){
		return this.frame;
	}
	
	public void quit() {
		client.gameWindowClosing( game.getGameID() );
	}

	/**
	 * Remove the specified piece from the graveyard and place it 
	 * on the board at location.
	 * 
	 * @param piece
	 * @param location
	 */
	public void placePiece(PlayerPiece piece, Location location) {
		try {
			getGameWindowFrame().placePiece( piece, location );
		} catch (InitialPlacementError e) {
			Dialog.displayPiecePlacementFailedDialog();
		}
	}

	/**
	 * Indicates the game board has been updated with the indicated move.
	 * @param from
	 * @param to
	 */
	public void movePiece( PlayerPiece piece, Location from, Location to ) {
		frame.movePiece( piece, from, to );
		frame.clearMyTurn();
	}

	/**
	 * Removes a piece from the gameboard.
	 * @param piece
	 */
	public void removePiece(PlayerPiece piece, Location from) {
		frame.removePiece(piece, from);
	}
	
	/**
	 * Disables the click listeners until it's your turn again.
	 */
	public void haltListeners() {
		frame.haltListeners(true);
	}

	/**
	 * Updates the game board with the result of an attack.
	 * @param attacker  the piece doing the attacking
	 * @param from  location of the attacking piece
	 * @param defender  the piece being attacked
	 * @param to  location of the piece being attacked
	 */
	public void attackPiece(PlayerPiece attacker, Location from, PlayerPiece defender, Location to) {
		
		frame.getBoardSquare( from ).removePiece();
		frame.getBoardSquare( to ).removePiece();
		
		System.out.println("Attack called");
		Location attackerLocation = attacker.getLocation();		// may be graveyard or null
		Location defenderLocation = defender.getLocation();		// may be graveyard or null
		
		if ((attackerLocation == null) || (attackerLocation.isInBoneyard())) {
			// return to graveyard
			System.out.println("Drop attacker in graveyard");
			frame.putInGraveyard( attacker );
		} else {
			System.out.println("attacker X " + attackerLocation.getXCoordinate());
			// put on gameboard
			GameBoardSquare attackerDest = frame.getBoardSquare( attackerLocation );
			attackerDest.addPiece(attacker);
		}
		
		if ((defenderLocation == null) || (defenderLocation.isInBoneyard())) {
			// return to graveyard
			System.out.println("Drop defender in graveyard");
			if(defender.getRank() == -1) 
				System.out.println("Hidden defender");
			frame.putInGraveyard( defender );
		} else {
			// put on gameboard
			GameBoardSquare defenderDest = frame.getBoardSquare( defenderLocation );
			defenderDest.addPiece(defender);
		}

		AttackDialog dialog = new AttackDialog(frame, false, attacker, defender);
		dialog.setVisible(true);

		frame.clearMyTurn();
	}

	/**
	 * Indicates to the user that the game has ended, either in victory or defeat.
	 * @param winner  specifies whether the player has won (true) or lost (false)
	 */
	public void gameOver(boolean winner) {
		GameBoardPanel panel = frame.getGamePanel();
		if(winner){
			JOptionPane.showMessageDialog(panel, "You Win!",
					"Victory!!!",JOptionPane.WARNING_MESSAGE);
		} else {
			JOptionPane.showMessageDialog(panel, "You Lose!",
					"Defeat!!!",JOptionPane.WARNING_MESSAGE);
		}
		frame.changeQuitButton();
	}

	public void gameStarted() {
		this.frame.gameStarted();
	}

	/**
	 * This function should be called when the opponent has joined the game, and
	 * the opponent name can now be retrieved and displayed on the graveyard.
	 */
	public void opponentJoined() {
		// update the opponent graveyard to indicate the opponent name and track the
		// opponent initial piece placement
		frame.opponentJoined();
	}

	public void myTurn() {
		// show an indicator that it is now the players turn
		
		//GameBoardPanel panel = frame.getGamePanel();
		//JOptionPane.showMessageDialog(panel, "It's your turn!",
		//			"Your Turn", JOptionPane.WARNING_MESSAGE);
		
		frame.haltListeners(false);
		frame.setMyTurn();
	}

	public void opponentQuit() {
		GameBoardPanel panel = frame.getGamePanel();
		JOptionPane.showMessageDialog(panel, "Your Opponent has surrendered!",
				"Victory!!!",JOptionPane.WARNING_MESSAGE);
	}

	public long getGameID() {
		return game.getGameID();
	}

	public void opponentReady() {
		frame.opponentReady();
	}
}


/**
 * Dialog that appears when a piece has attacked another piece.  Both team's
 * colors and pieces are displayed in the dialog.
 * 
 * @author ansawchu
 *
 */
@SuppressWarnings("serial")
class AttackDialog extends JDialog implements ActionListener {
    private JPanel myPanel = null;

    public AttackDialog(JFrame frame, boolean modal, PlayerPiece attacker, PlayerPiece defender) {
        super(frame, modal);
        myPanel = new JPanel();
        getContentPane().add(myPanel);
        setTitle("Attack!");

        // Create the components
        JLabel msg = new JLabel("     The " +
        		attacker.getColor() + " " + attacker.getName() +
				" has attacked the " +
        		defender.getColor() + " " + defender.getName() + "!     ");
        JButton okButton = new JButton("OK");
        okButton.addActionListener(this);

	    Dimension dim = new Dimension();
    	dim.width = 40;
    	dim.height = 60;
    	
	    StrategoPieceImage pieceImageAttack = StrategoPieceImage.get(attacker.getPieceType());
    	BufferedImage imgAttack = pieceImageAttack.getScaledImage(attacker.getColor(), dim);
    	JLabel attackerLabel = new JLabel(new ImageIcon(imgAttack));

	    StrategoPieceImage pieceImageDefend = StrategoPieceImage.get(defender.getPieceType());
    	BufferedImage imgDefend = pieceImageDefend.getScaledImage(defender.getColor(), dim);
    	JLabel defenderLabel = new JLabel(new ImageIcon(imgDefend));

    	InputStream imageStream = this.getClass().getResourceAsStream("/edu/wpi/cs509/ui/images/attack-icon.png");
    	BufferedImage img3 = null;
		try {
			img3 = ImageIO.read(imageStream);
		} catch (IOException e) {
			System.out.println("Unable to read attack icon image");
			e.printStackTrace();
		}
    	JLabel attackLabel = new JLabel(new ImageIcon(img3));

    	JLabel blankLabel1 = new JLabel(" ");
    	JLabel blankLabel2 = new JLabel(" ");
    	JLabel blankLabel3 = new JLabel(" ");
    	JLabel blankLabel4 = new JLabel(" ");
    	
	    // Position the buttons, labels, and images
	    GridBagConstraints c = new GridBagConstraints(); // Holds constraints for GUI components.
	    GridBagLayout gridbag = new GridBagLayout();
	    myPanel.setLayout(gridbag);
	
	    // These constraints apply to all components
	    c.fill = GridBagConstraints.HORIZONTAL;
	    c.weightx = 0.5;
	    c.anchor = GridBagConstraints.CENTER;
	    
	    // Row 1: use blank labels to space things properly
	    c.gridx = 0;
	    c.gridy = 0;
	    c.gridwidth = 5;
	    gridbag.setConstraints(blankLabel1, c);
	    myPanel.add(blankLabel1);
	    
	    // Row 2: attack message
	    c.gridx = 0;
	    c.gridy = 1;
	    c.gridwidth = 5;
	    msg.setAlignmentX(CENTER_ALIGNMENT);
	    msg.setAlignmentY(CENTER_ALIGNMENT);
	    gridbag.setConstraints(msg, c);
	    myPanel.add(msg);
	    
	    // Row 3: blank label
	    c.gridx = 0;
	    c.gridy = 2;
	    c.gridwidth = 5;
	    gridbag.setConstraints(blankLabel2, c);
	    myPanel.add(blankLabel2);

	    // Row 4: attacker and defender piece icons, with attack icon in between
	    c.gridx = 1;
	    c.gridy = 3;
	    c.gridwidth = 1;
	    gridbag.setConstraints(attackerLabel, c);
	    myPanel.add(attackerLabel);

	    c.gridx = 2;
	    c.gridy = 3;
	    c.gridwidth = 1;
	    gridbag.setConstraints(attackLabel, c);
	    myPanel.add(attackLabel);

	    c.gridx = 3;
	    c.gridy = 3;
	    c.gridwidth = 1;
	    gridbag.setConstraints(defenderLabel, c);
	    myPanel.add(defenderLabel);

	    // Row 5: blank label
	    c.gridx = 0;
	    c.gridy = 4;
	    c.gridwidth = 5;
	    gridbag.setConstraints(blankLabel3, c);
	    myPanel.add(blankLabel3);

	    // Row 6: "OK" button
	    c.gridx = 2;
	    c.gridy = 5;
	    c.gridwidth = 1;
	    gridbag.setConstraints(okButton, c);
	    myPanel.add(okButton);

	    // Row 7: blank label
	    c.gridx = 0;
	    c.gridy = 6;
	    c.gridwidth = 5;
	    gridbag.setConstraints(blankLabel4, c);
	    myPanel.add(blankLabel4);

	    pack();
        setLocationRelativeTo(frame);
        setVisible(true);
    }

    public void actionPerformed(ActionEvent e) {
    	setVisible(false);
    }
    
}
